package org.proteored.miapeapi.xml.pride.adapter;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.cv.msi.MatchedPeaks;
import org.proteored.miapeapi.cv.msi.ProteinDescription;
import org.proteored.miapeapi.cv.msi.ValidationType;
import org.proteored.miapeapi.exceptions.IllegalMiapeArgumentException;
import org.proteored.miapeapi.experiment.model.ExtendedIdentifiedPeptide;
import org.proteored.miapeapi.interfaces.Adapter;
import org.proteored.miapeapi.interfaces.Software;
import org.proteored.miapeapi.interfaces.msi.Database;
import org.proteored.miapeapi.interfaces.msi.IdentifiedPeptide;
import org.proteored.miapeapi.interfaces.msi.IdentifiedProtein;
import org.proteored.miapeapi.interfaces.msi.MiapeMSIDocument;
import org.proteored.miapeapi.interfaces.msi.ProteinScore;
import org.proteored.miapeapi.xml.pride.autogenerated.GelFreeIdentificationType;
import org.proteored.miapeapi.xml.pride.autogenerated.ObjectFactory;
import org.proteored.miapeapi.xml.pride.autogenerated.Peptide;
import org.proteored.miapeapi.xml.pride.util.PrideControlVocabularyXmlFactory;

public class GelFreeIdentificationAdapter implements
		Adapter<GelFreeIdentificationType> {
	private static Logger log = Logger.getLogger("log4j.logger.org.proteored");
	private final ObjectFactory factory;
	private final ControlVocabularyManager cvManager;
	private final PrideControlVocabularyXmlFactory prideCvUtil;
	private final IdentifiedProtein protein;
	private final MiapeMSIDocument miapeMSI;
	private final boolean includeSpectra;

	public GelFreeIdentificationAdapter(ObjectFactory factory,
			ControlVocabularyManager cvManager, IdentifiedProtein protein,
			MiapeMSIDocument miapeMSI, boolean includeSpectra) {
		this.factory = factory;
		this.cvManager = cvManager;
		this.protein = protein;
		this.miapeMSI = miapeMSI;
		this.prideCvUtil = new PrideControlVocabularyXmlFactory(factory,
				cvManager);
		this.includeSpectra = includeSpectra;
	}

	@Override
	public GelFreeIdentificationType adapt() {
		GelFreeIdentificationType gelFreeIdentification = factory
				.createGelFreeIdentificationType();
		;
		String accession = null;
		try {
			accession = protein.getAccession().trim();
		} catch (UnsupportedOperationException ex) {
			accession = "Not assigned protein";
		}

		try {
			if (accession.contains(".")) {
				log.info("adding gelfreeidentification con version: "
						+ accession);
				String[] tmp = accession.split(".");
				accession = tmp[0];
				log.info("adding gelfreeidentification sin version: "
						+ accession);
				final String accVersion = tmp[1];
				log.info("adding gelfreeidentification version: " + accVersion);
				gelFreeIdentification.setAccessionVersion(accVersion);
			}
		} catch (IndexOutOfBoundsException ex) {
			// do nothing
		}
		log.debug("Adding gelFreeIndentification: " + accession);
		gelFreeIdentification.setAccession(accession);

		try {
			gelFreeIdentification.setSequenceCoverage(Double.valueOf(protein
					.getCoverage()) / 100);
		} catch (Exception e) {
			// DO NOTHING
		}
		try {
			if (protein.getScores() != null) {
				// take the first element in the set
				final ProteinScore proteinScore = protein.getScores()
						.iterator().next();
				// take the value of the score
				gelFreeIdentification.setScore(Double.valueOf(proteinScore
						.getValue()));
			}
		} catch (Exception e) {
			// DO NOTHING
		}
		// Check if databases are stated in MIAPE MSI. Only the first will be
		// added to the protein
		if (miapeMSI.getInputParameters() != null) {
			if (miapeMSI.getInputParameters().iterator().next().getDatabases() != null) {
				Database database = miapeMSI.getInputParameters().iterator()
						.next().getDatabases().iterator().next();
				final String name = database.getName();
				gelFreeIdentification.setDatabase(name);
				String numVersion = database.getNumVersion();
				if (!name.equals(numVersion)) {
					if (numVersion.length() > 30) {
						log.debug("Truncating database version to 30 characteres allowed in PRIDE DB");
						numVersion = numVersion.substring(0, 29);
					}
					gelFreeIdentification.setDatabaseVersion(numVersion);
				}
				// ParamType param = factory.createParamType();
				// TODO move the following code to another location in the file
				/*
				 * if (database.getDescription() != null) {
				 * Utils.addUserParam(factory, "Content of the databank",
				 * database.getDescription(), param.getCvParamOrUserParam()); }
				 * if (database.getSequenceNumber() != null) {
				 * Utils.addUserParam(factory,
				 * "Number of sequences in the database",
				 * database.getSequenceNumber(), param.getCvParamOrUserParam());
				 * } if (param.getCvParamOrUserParam().size() > 0) {
				 * gelFreeIdentification.setAdditional(param); }
				 */
				// Utils.addCVParam(factory, "PSI:1000026", Utils.PSI_CV_LABEL,
				// "Detector Type", detector.getName(),
				// param.getCvParamOrUserParam());

			}
		}

		if (miapeMSI.getSoftwares() != null
				&& miapeMSI.getSoftwares().size() > 0) {
			Software software = miapeMSI.getSoftwares().iterator().next();
			gelFreeIdentification.setSearchEngine(software.getName());

		}
		addPeptides(gelFreeIdentification, protein.getIdentifiedPeptides());
		addAdditionalParameters(gelFreeIdentification, protein);
		return gelFreeIdentification;

	}

	private void addPeptides(GelFreeIdentificationType xmlProtein,
			List<IdentifiedPeptide> identifiedPeptides) {
		log.debug("adding peptides");
		Set<Integer> peptideIds = new HashSet<Integer>();
		for (IdentifiedPeptide identifiedPeptide : identifiedPeptides) {
			if (!peptideIds.contains(identifiedPeptide.getId())) {
				peptideIds.add(identifiedPeptide.getId());
				ExtendedIdentifiedPeptide extendedIdentifiedPeptide = new ExtendedIdentifiedPeptide(
						null, null, identifiedPeptide, null);
				try {
					Peptide xmlPeptide = new PeptideAdapter(factory, cvManager,
							extendedIdentifiedPeptide, this.includeSpectra)
							.adapt();
					xmlProtein.getPeptideItem().add(xmlPeptide);
				} catch (IllegalMiapeArgumentException e) {
					log.warn(e.getMessage());
				}
			}
		}

	}

	private void addAdditionalParameters(
			GelFreeIdentificationType gelFreeIdentification,
			IdentifiedProtein protein) {
		try {
			if (gelFreeIdentification.getAdditional() == null)
				gelFreeIdentification.setAdditional(factory.createParamType());
			if (protein.getDescription() != null
					&& !"".equals(protein.getDescription())) {
				prideCvUtil.addCvParamToParamType(gelFreeIdentification
						.getAdditional(),
						ProteinDescription.PSI_PROTEIN_DESCRIPTION
								.getTermAccession(),
						ProteinDescription.PSI_PROTEIN_DESCRIPTION
								.getPreferredName(), protein.getDescription(),
						ProteinDescription.PSI_PROTEIN_DESCRIPTION.getCVRef());
			}
			if (protein.getValidationStatus() != null
					&& !"".equals(protein.getValidationStatus())) {
				prideCvUtil
						.addUserParamToParamType(
								gelFreeIdentification.getAdditional(),
								PrideControlVocabularyXmlFactory.VALIDATION_STATUS_TEXT,
								protein.getValidationStatus().toString());
			}
			if (protein.getValidationType() != null
					&& !"".equals(protein.getValidationType())) {
				prideCvUtil.addCvParamOrUserParamToParamType(
						gelFreeIdentification.getAdditional(),
						protein.getValidationType(),
						protein.getValidationValue(),
						ValidationType.getInstance(cvManager));
			}
			if (protein.getPeaksMatchedNumber() != null
					&& !"".equals(protein.getPeaksMatchedNumber())) {
				prideCvUtil
						.addCvParamToParamType(gelFreeIdentification
								.getAdditional(),
								MatchedPeaks.NUMBER_OF_MATCHED_PEAKS
										.getTermAccession(),
								MatchedPeaks.NUMBER_OF_MATCHED_PEAKS
										.getPreferredName(), protein
										.getPeaksMatchedNumber(),
								MatchedPeaks.NUMBER_OF_MATCHED_PEAKS.getCVRef());
			}
			if (protein.getUnmatchedSignals() != null
					&& !"".equals(protein.getUnmatchedSignals())) {
				prideCvUtil.addCvParamToParamType(gelFreeIdentification
						.getAdditional(),
						MatchedPeaks.NUMBER_OF_UNMATCHED_PEAKS
								.getTermAccession(),
						MatchedPeaks.NUMBER_OF_UNMATCHED_PEAKS
								.getPreferredName(), protein
								.getUnmatchedSignals(),
						MatchedPeaks.NUMBER_OF_UNMATCHED_PEAKS.getCVRef());
			}

			// In order to support PRIDE Viewer bug, if additional is empty, put
			// something
			if (gelFreeIdentification.getAdditional().getCvParamOrUserParam() == null
					|| gelFreeIdentification.getAdditional()
							.getCvParamOrUserParam().isEmpty()) {
				prideCvUtil.addCvParamOrUserParamToParamType(
						gelFreeIdentification.getAdditional(),
						"No additional information", null, null);
			}
		} catch (UnsupportedOperationException ex) {
			// do nothing
		}
	}
}
